package com.luoqiz.common.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 时间工具
 * 
 * @author luoqiz
 *
 */
public class TimeUtils {

	public static final long MILLIS_PER_SECOND = 1000;
	public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
	public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
	public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;

	public static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss";

	public static final int SEMI_MONTH = 1001;

	/**
	 * 将传入的calendar转为当日凌晨的calendar
	 * 
	 * @param calendar
	 * @return
	 */
	public static Calendar calendarToWeeHours(Calendar calendar) {
		// 时
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		// 分
		calendar.set(Calendar.MINUTE, 0);
		// 秒
		calendar.set(Calendar.SECOND, 0);
		// 毫秒
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar;
	}

	/**
	 * 将指定的时间位清零
	 * 
	 * @param calendar
	 * @param type
	 * @return
	 */
	public static Calendar calendarClear(Calendar calendar, Integer... typeArray) {

		if (typeArray == null) {
			return calendar;
		}
		for (int type : typeArray) {
			switch (type) {
			case 0:
				break;

			case Calendar.HOUR_OF_DAY:
				calendar.set(Calendar.HOUR_OF_DAY, 0);
				break;

			case Calendar.HOUR:
				calendar.set(Calendar.HOUR, 0);
				break;

			case Calendar.MINUTE:
				calendar.set(Calendar.MINUTE, 0);
				break;

			case Calendar.SECOND:
				calendar.set(Calendar.SECOND, 0);
				break;

			case Calendar.MILLISECOND:
				calendar.set(Calendar.MILLISECOND, 0);
				break;

			default:
				break;
			}
		}
		return calendar;
	}

	/**
	 * 获取传入时间所在周内的星期i的凌晨时间,以周日为起始
	 * 
	 * @param date
	 * @param i    本周内的第几天。0未周日，也是一周的开始
	 * @return
	 */
	public static Date currentWeekDate(Date date, int i) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int weekOffset = calendar.get(Calendar.DAY_OF_WEEK);
		// 当周凌晨时间
		calendar.add(Calendar.DATE, 1 - weekOffset);
		calendarToWeeHours(calendar);
		calendar.add(Calendar.DATE, i);
		return calendar.getTime();
	}

	/**
	 * 获取传入时间所在月内的第i天的凌晨时间
	 * 
	 * @param date
	 * @param i    本月内的第几天。
	 * @return
	 */
	public static Date currentMonthDate(Date date, int i) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int monthOffset = calendar.get(Calendar.DAY_OF_MONTH);
		// System.out.println("月内天数偏移量：" + monthOffset);
		// 当周凌晨时间
		calendar.add(Calendar.DATE, -monthOffset);
		calendarToWeeHours(calendar);
		calendar.add(Calendar.DATE, i);
		return calendar.getTime();
	}

	/**
	 * 获取传入时间计算所在当天的凌晨时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date dateToWeeHoursDate(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendarToWeeHours(calendar);
		return calendar.getTime();
	}

	public static Date dateToWeeHoursDate(Long times) {
		Date date = new Date();
		if (times != null) {
			date = new Date(times);
		}
		return dateToWeeHoursDate(date);
	}

	/**
	 * 根据传入的两个时间，计算相差的理论日期天数(以天数计算相差，绝对值) 例如：startDdate(2018-1-19 23:59:59) 和
	 * endDate(2018-1-20 0:0:0)返回结果为1
	 * 
	 * @param date
	 * @return
	 */
	public static int offsetAbsDayForDay(Date startDdate, Date endDate) {
		long time1 = dateToWeeHoursDate(startDdate).getTime();
		long time2 = dateToWeeHoursDate(endDate).getTime();
		return offsetAbsDayForDay(time1, time2);
	}

	public static int offsetAbsDayForDay(Long startTime, Long endTime) {
		long offSecond = Math.abs(startTime - endTime);
		return (int) (offSecond / MILLIS_PER_DAY);
	}

	/**
	 * 根据传入的两个时间，计算相差的理论日期天数(以天数计算相差，有正负，date1-date2) 例如：date1(2018-1-19 23:59:59) 和
	 * date2(2018-1-20 0:0:0)返回结果为-1
	 * 
	 * @param date
	 * @return
	 */
	public static int offsetDayForDay(Date date1, Date date2) {
		long time1 = dateToWeeHoursDate(date1).getTime();
		long time2 = dateToWeeHoursDate(date2).getTime();
		long offSecond = time1 - time2;
		return (int) (offSecond / MILLIS_PER_DAY);
	}

	/**
	 * 根据传入的两个时间，计算相差的实际天数(以秒数计算相差) 例如：date1(2018-1-19 23:59:59) 和 date2(2018-1-20
	 * 0:0:0)返回结果为0
	 * 
	 * @param date
	 * @return
	 */
	public static long offsetDayForSecond(Date date1, Date date2) {
		long offSecond = Math.abs(date1.getTime() - date2.getTime());
		return offSecond / MILLIS_PER_DAY;
	}

	/**
	 * 根据传入的两个时间，计算相差的实际小时数(以秒数计算相差)
	 * 
	 * @param date
	 * @return
	 */
	public static long offsetHoursAbsForSecond(Date date1, Date date2) {
		long offSecond = Math.abs(date1.getTime() - date2.getTime());
		return offSecond / MILLIS_PER_HOUR;
	}

	public static long offsetHoursForSecond(Date date1, Date date2) {
		int symbol = date1.before(date2) ? -1 : 1;
		return offsetHoursAbsForSecond(date1, date2) * symbol;
	}

	/**
	 * 根据传入的两个时间，计算相差的实际绝对分钟数(以秒数计算相差)
	 * 
	 * @param date
	 * @return
	 */
	public static long offsetMinuteAbsForSecond(Date date1, Date date2) {
		long offSecond = Math.abs(date1.getTime() - date2.getTime());
		return offSecond / MILLIS_PER_MINUTE;
	}

	public static long offsetMinuteForSecond(Date date1, Date date2) {
		int symbol = date1.before(date2) ? -1 : 1;
		return offsetMinuteAbsForSecond(date1, date2) * symbol;
	}

	/**
	 * 根据传入的时间，获取指定天数前或后的日期
	 * @param date
	 * @param offset
	 * @param isWeeHours
	 * @return
	 */
	public static Date addDateOffsetDay(Date date, int offset, boolean isWeeHours) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		if (isWeeHours) {
			calendarToWeeHours(calendar);
		}
		calendar.add(Calendar.DATE, offset);
		return calendar.getTime();
	}

	public static Date addDateOffsetDay(Date date, int offset) {
		return addDateOffsetDay(date, offset, false);
	}

	/**
	 * 根据传入的时间，获取指定小时前或后的日期
	 * 
	 * @param date
	 * @param offset
	 * @param typeArray
	 * @return
	 */
	public static Date addDateOffsetHour(Date date, int offset, Integer... typeArray) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		if (typeArray != null) {
			calendarClear(calendar, typeArray);
		}

		calendar.add(Calendar.HOUR, offset);
		return calendar.getTime();
	}

	public static Date addDateOffsetHour(Date date, int offset) {
		return addDateOffsetHour(date, offset, 0);
	}

	/**
	 * 根据传入的时间，获取指定分钟前或后的日期
	 * 
	 * @param date
	 * @param offset
	 * @param isWeeHours 時分秒是否清零
	 * @return
	 */
	public static Date addDateOffsetMinute(Date date, int offset, Integer... typeArray) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		if (typeArray != null) {
			calendarClear(calendar, typeArray);
		}
		calendar.add(Calendar.MINUTE, offset);
		return calendar.getTime();
	}


	/**
	 * 根据传入的时间，获取指定格式的日期
	 * 
	 * @param date   需要格式化的时间
	 * @param offset 格式化的样式
	 * @return
	 */
	public static String dateFormat(Date date, String pattern) {
		if (pattern == null) {
			pattern = DATE_FORMAT_PATTERN;
		}
		SimpleDateFormat format = new SimpleDateFormat(pattern);
		return format.format(date);
	}

	public static String dateFormat(Long dateTime, String pattern) {
		return dateFormat(new Date(dateTime), pattern);
	}

	public static String dateFormat(Date date) {
		return dateFormat(date, null);
	}

	public static String dateFormat(Long dateTime) {
		return dateFormat(new Date(dateTime), null);
	}

	/**
	 * 根据传入的时间，获取指定格式的日期
	 * 
	 * @param formatDate 需要格式化的样式时间
	 * @param pattern    格式化的样式
	 * @return
	 */
	public static Date dateFormat(String formatDate, String pattern) {
		if (pattern == null) {
			pattern = DATE_FORMAT_PATTERN;
		}
		DateFormat format = new SimpleDateFormat(pattern);
		Date date = null;
		try {
			date = format.parse(formatDate);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}

	public static Date dateFormat(String formatDate) {
		return dateFormat(formatDate, null);
	}

	/**
	 * 功能描述：返回月
	 *
	 * @param date Date 日期
	 * @return 返回月份
	 */
	public static int getMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.MONTH) + 1;
	}

	/**
	 * 功能描述：返回日
	 *
	 * @param date Date 日期
	 * @return 返回日份
	 */
	public static int getDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 功能描述：返回小时
	 *
	 * @param date 日期
	 * @return 返回小时
	 */
	public static int getHour(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * 功能描述：返回分钟
	 *
	 * @param date 日期
	 * @return 返回分钟
	 */
	public static int getMinute(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * 返回秒钟
	 *
	 * @param date Date 日期
	 * @return 返回秒钟
	 */
	public static int getSecond(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.SECOND);
	}

	/**
	 * 功能描述：返回毫秒
	 *
	 * @param date 日期
	 * @return 返回毫
	 */
	public static long getMillis(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.getTimeInMillis();
	}

	public static void main(String[] args) {

		System.out.println(TimeUtils.currentMonthDate(new Date(), 0).getTime());
		System.out.println("---------------------------------");
		Date date1 = new Date(1532962800000l);
		Date date2 = new Date(1532966400000l);
		System.out.println("以天数计算天数相差：" + (TimeUtils.offsetAbsDayForDay(date1, date2)));
		System.out.println("以秒数计算天数相差：" + (TimeUtils.offsetDayForSecond(date1, date2)));

		System.out.println("---------------------------------");
		Date d = TimeUtils.addDateOffsetDay(new Date(), -1, true);
		String formatDate = TimeUtils.dateFormat(d, DATE_FORMAT_PATTERN);
		System.out.println(formatDate);
		Date formatd = TimeUtils.dateFormat(formatDate, DATE_FORMAT_PATTERN);
		System.out.println(formatd);
		System.out.println(TimeUtils.dateFormat(formatd, null));

		System.out.println("---------------------------------");

		Date currentDate = new Date();
		Date weeHours = TimeUtils.dateToWeeHoursDate(currentDate);
		System.out.println("以秒数计算小时数绝对值相差：" + TimeUtils.offsetHoursAbsForSecond(currentDate, weeHours));
		System.out.println("以秒数计算小时数相对值相差：" + TimeUtils.offsetHoursForSecond(weeHours, currentDate));

		System.out.println("---------------------------------");

		Date addDateOffsetHourDate = TimeUtils.addDateOffsetHour(currentDate, 5);
		System.out.println("以小时计算指定n小时前后的时间：" + TimeUtils.dateFormat(addDateOffsetHourDate, null));

		System.out.println("---------------------------------");
		Date beforDateForTwoHourClear = TimeUtils.addDateOffsetHour(currentDate, -1, Calendar.MINUTE, Calendar.SECOND,
				Calendar.MILLISECOND);
		System.out.println("以小时计算指定n小时前后的时间并将分钟、秒、毫秒清零：" + TimeUtils.dateFormat(beforDateForTwoHourClear));
	}

}
